﻿using CommonFP;
using Microsoft.Extensions.Configuration;
using SqlSugar;
using System;
using System.Linq;

namespace CommonDevelop
{
    /// <summary>
    /// appsettings.json配置管理器
    /// </summary>
    public static class ConfigHelper
    {
        //ReloadOnChange = true 当appsettings.json被修改时重新加载
        private static readonly IConfigurationRoot ConfigurationRoot = new ConfigurationBuilder()
                   .AddInMemoryCollection()    //将配置文件的数据加载到内存中
                   .SetBasePath(AppContext.BaseDirectory)   //指定配置文件所在的目录
                   .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)  //指定加载的配置文件
                   .Build();    //编译成对象  

        /// <summary>
        /// 获取连接字符串
        /// </summary>
        public static string GetConnectionString(string connStr)
            => ConfigurationRoot.GetConnectionString(connStr);

        /// <summary>
        /// 获取配置映射（有可能取不到值，请判断元组）
        /// </summary>
        public static (T En, string error) GetSettings<T>()
            where T : class
            => FP.Try(() => ConfigurationRoot.GetSection(typeof(T).Name).Get<T>())
            .Run().Match(
                Exception: e => (default(T), e.Message),
                Success: a => (a, string.Empty));

        /// <summary>
        /// 获取配置映射
        /// </summary>
        public static T GetSettings<T>(string Name)
            where T : class
            => FP.Try(() => ConfigurationRoot.GetSection(Name).Get<T>())
            .Run().Outcome();

        /// <summary>
        /// 获取配置片段
        /// </summary>
        public static IConfigurationSection GetSection(string Name)
            => ConfigurationRoot.GetSection(Name);

        /// <summary>
        /// 获取配置键值
        /// </summary>
        public static string GetConfigValue(string keyStr)
        {
            var configRootList = ConfigurationRoot.AsEnumerable().ToList();
            var configKpv = configRootList.FirstOrDefault(m => m.Key == keyStr);
            if (configKpv.Key != null)
                return configKpv.Value;
            else
                return null;
        }

        /// <summary>
        /// 获取数据库配置环境
        /// </summary>
        public static ConnectionConfig GetSugarSettings(ref ConnectionConfig ReadOnlyConfig)
        {
            ConnectionConfig config = null;
            ReadOnlyConfig = null;
            try
            {
                var cs = ConfigurationRoot.GetSection(nameof(SugarConfig));
                var en = cs.Get<SugarConfig>();

                DbType dbt = DbType.SqlServer;
                switch (en.DbType)
                {
                    case "Oracle":
                        dbt = DbType.Oracle;
                        break;
                    case "MySql":
                        dbt = DbType.MySql;
                        break;
                    case "Sqlite":
                        dbt = DbType.Sqlite;
                        break;
                    case "PostgreSQL":
                        dbt = DbType.PostgreSQL;
                        break;
                    default:
                        dbt = DbType.SqlServer;
                        break;
                }

                bool AutoCloseConnection = en.IsAutoCloseConnection.Equals("true", StringComparison.OrdinalIgnoreCase);
                config = new ConnectionConfig()
                {
                    ConnectionString = en.ConnectionString, //必填
                    DbType = dbt, //必填
                    IsAutoCloseConnection = AutoCloseConnection, //默认false
                    InitKeyType = InitKeyType.SystemTable
                };
                ReadOnlyConfig = new ConnectionConfig()
                {
                    ConnectionString = en.ReadOnlyConnectionString, //必填
                    DbType = dbt, //必填
                    IsAutoCloseConnection = AutoCloseConnection, //默认false
                    InitKeyType = InitKeyType.SystemTable
                };
            }
            catch
            {
                config = null;
                ReadOnlyConfig = null;
            }
            return config;
        }

        public static (string connectionString, string provider) GetSugarEx()
            => FP.Try(() =>
            {
                var cs = ConfigurationRoot.GetSection(nameof(SugarConfig));
                var en = cs.Get<SugarConfig>();
                return (en.SchedulerConnection, en.DbType);
            }).Run().Match(e => (null, null), a => a);

        //函数式编程，在确认没有突变的情况下，进入状态模式，支持并发；只要保证顶层框架没有突变，就能套用FP模式进行实现业务代码
        //编程方式与DDD无关，DDD与AOP是架构层面的布局，编程方式只保证场景实现的可能

        public static Option<T> Lookup<T>(this IConfigurationRoot config, params string[] path)
            => (T)Convert.ChangeType(config.GetSection(path).Value, typeof(T));

        public static Option<string> Lookup(this IConfigurationRoot config, params string[] path)
            => config.GetSection(path).Value;

        public static IConfigurationSection GetSection(this IConfigurationRoot config, params string[] path)
            => (IConfigurationSection)path.Aggregate(config as IConfiguration, (parent, name) => parent.GetSection(name));

    }
}
